
import random
from SAGIN_Progrem.entity.Structure import Queue
from SAGIN_Progrem.entity.Formulas import Formulas
from SAGIN_Progrem.entity.Appliances import Appliances
from SAGIN_Progrem.entity.Cloud import Cloud
from threading import Lock, Thread

def random_a():
    if random.random() < 0.5:
        a = 1       # 卸载
    else:
        a = 0       # 本地
    return a

class Satellite:

    B = 1000000 # 带宽1MHz
    P = 30 # 传输功率 30dBm
    f = 4800000000 # CPU频率 5GC/s

    formulas = Formulas(B, P, f)

    def __init__(self):
        self.computing_queue = Queue(20)
        self.offloading_queue = Queue(20)
        self.sa_off_num = 0  # 卫星卸载个数
        self.sa_lo_num = 0  # 卫星本地计算个数

    # 向云服务器卸载任务
    def off_to_cloud(self, task_list, step_time): #
        round_ = step_time
        delay_w_temp = 0 # 用于记录等待时间
        num = 0
        off_cloud_list = []
        while True:
            while not self.offloading_queue.isMAX():
                if num < len(task_list):
                    self.offloading_queue.enQueue(task_list[num])
                    num += 1
                else:
                    break
            for i in range(0, self.offloading_queue.size()):
            # with lock:
                task = self.offloading_queue.get_hand()
                task_index = task.get_task_index()
                delay = self.formulas.transmission_sa_Delay(task)
                if round_ >= delay:
                    task.delay['wait'] += delay_w_temp
                    task.delay['transmission'] += delay
                    # cloud.computing_queue.enQueue(self.offloading_queue.get_hand())
                    delay_w_temp += self.formulas.transmission_Delay(task) # 等待延迟只记录任务的传输延迟，不记录传播延迟
                    off_cloud_list.append(task)
                    self.offloading_queue.deQueue()
                    # self.sa_off_num += 1
                    round_ -= delay
                else:
                    for j in range(0, self.offloading_queue.size()):
                        self.offloading_queue.items[j].delay['wait'] += delay_w_temp
                    round_ = 0
                    return off_cloud_list

            if num >= len(task_list):
                return off_cloud_list
        # print('sate_off_end\n')

    def off_to_cloud_(self, task_list, app_list, step_time): #
        round_ = step_time
        delay_w_temp = 0 # 用于记录等待时间
        num = 0
        off_cloud_list = []
        while True:
            while not self.offloading_queue.isMAX():
                if num < len(task_list):
                    self.offloading_queue.enQueue(task_list[num])
                    num += 1
                else:
                    break
            for i in range(0, self.offloading_queue.size()):
            # with lock:
                task = self.offloading_queue.get_hand()
                task_index = task.get_task_index()
                delay = self.formulas.transmission_sa_Delay(task)
                if round_ >= delay / 2:
                    app_list[task.id].task_app_one_list[task_index].delay['wait'] += delay_w_temp
                    app_list[task.id].task_app_one_list[task_index].delay['transmission'] += delay
                    # cloud.computing_queue.enQueue(self.offloading_queue.get_hand())
                    delay_w_temp += (delay / 2) # 等待延迟只记录任务的传输延迟，不记录传播延迟
                    off_cloud_list.append(task)
                    self.offloading_queue.deQueue()
                    # self.sa_off_num += 1
                    round_ -= (delay / 2)
                else:
                    for j in range(0, self.offloading_queue.size()):
                        self.offloading_queue.items[j].delay['wait'] += delay_w_temp
                    round_ = 0
                    return

            if num >= len(task_list):
                return off_cloud_list

    def off_to_cloud__(self, task_list, app_list, step_time): #
        round_ = step_time
        delay_w_temp = 0 # 用于记录等待时间
        num = 0
        off_cloud_list = []
        while True:
            while not self.offloading_queue.isMAX():
                if num < len(task_list):
                    self.offloading_queue.enQueue(task_list[num])
                    num += 1
                else:
                    break
            for i in range(0, self.offloading_queue.size()):
            # with lock:
                task = self.offloading_queue.get_hand()
                task_index = task.get_task_index()
                delay = self.formulas.transmission_sa_Delay(task)
                if round_ >= delay / 2:
                    app_list[task.id].task_app_one_list[task_index].delay['wait'] += delay_w_temp
                    app_list[task.id].task_app_one_list[task_index].delay['transmission'] += delay
                    # cloud.computing_queue.enQueue(self.offloading_queue.get_hand())
                    delay_w_temp += (delay / 2) # 等待延迟只记录任务的传输延迟，不记录传播延迟
                    off_cloud_list.append(task)
                    self.offloading_queue.deQueue()
                    # self.sa_off_num += 1
                    round_ -= (delay / 2)
                else:
                    for j in range(0, self.offloading_queue.size()):
                        self.offloading_queue.items[j].delay['wait'] += delay_w_temp
                    round_ = 0
                    return

            if num >= len(task_list):
                return off_cloud_list
    # 卫星在本地计算任务
    def compute_task(self, task_list, app_list, step_time):
        round_ = step_time
        delay_w_temp = 0  # 用于记录等待时间
        num = 0
        while True:
            while not self.computing_queue.isMAX():
                if num < len(task_list):
                    self.computing_queue.enQueue(task_list[num])
                    num += 1
                else:
                    break
            for i in range(self.computing_queue.size()):
            # with lock:
                task = self.computing_queue.get_hand()
                task_index = task.get_task_index()
                # print(task.id)
                delay = self.formulas.compute_Delay(task)
                if round_ >= delay:
                    if random.random() < 0.3:
                        app_list[task.id].task_app_one_list[task_index].delay['wait'] += delay_w_temp
                    app_list[task.id].task_app_one_list[task_index].delay['compute'] += round(delay, 2)
                    app_list[task.id].task_app_one_list[task_index].finish = 2
                    delay_w_temp = round(delay, 2)
                    app_list[task.id].task_app_one_list[task_index].size_ = app_list[task.id].task_app_one_list[
                        task_index].size
                    # print(app_list[task.id].task_app_one_list[task_index].delay['compute'])
                    round_ -= delay
                    self.sa_lo_num += 1
                    self.computing_queue.deQueue()
                    # print(f'sate{task.taskid}')
                else:
                    app_list[task.id].task_app_one_list[task_index].delay['compute'] += round_
                    delay_w_temp = round_
                    size_down = ((round_ / 1000) * self.f) / task.complex
                    app_list[task.id].task_app_one_list[task_index].size_ -= size_down
                    for j in range(0, self.computing_queue.size()):
                        self.computing_queue.items[j].delay['wait'] += delay_w_temp
                    while not self.computing_queue.isMAX():
                        if num < len(task_list):
                            self.computing_queue.enQueue(task_list[num])
                            num += 1
                        else:
                            return
                    return
            if num >= len(task_list):
                return

    def compute_task_(self, task_list, step_time, action, step):
        round_ = step_time
        delay_w_temp = 0  # 用于记录等待时间
        num = 0
        off_num = round(len(task_list) * action)
        local_list = task_list[off_num:]
        off_list = task_list[:off_num]
        while True:
            while not self.computing_queue.isMAX():
                if num < len(local_list):
                    self.computing_queue.enQueue(local_list[num])
                    num += 1
                else:
                    break
            for i in range(self.computing_queue.size()):
                task = self.computing_queue.get_hand()
                task_index = task.get_task_index()
                delay = self.formulas.compute_Delay(task)
                if round_ >= delay:
                    if random.random() < 0.3:
                        task.delay['wait'] += delay_w_temp
                    task.delay['compute'] += round(delay, 2)
                    task.finish = 2
                    task.finish_step = step
                    delay_w_temp = round(delay, 2)
                    task.size_ = task.size
                    round_ -= delay
                    self.sa_lo_num += 1
                    self.computing_queue.deQueue()
                else:
                    task.delay['compute'] += round_
                    delay_w_temp = round_
                    size_down = ((round_ / 1000) * self.f) / task.complex
                    task.size_ -= size_down
                    for j in range(0, self.computing_queue.size()):
                        self.computing_queue.items[j].delay['wait'] += delay_w_temp
                    while not self.computing_queue.isMAX():
                        if num < len(task_list):
                            self.computing_queue.enQueue(task_list[num])
                            num += 1
                        else:
                            return off_list
                    return off_list
            if num >= len(local_list):
                return off_list

    # 卫星通过计算队列收集任务
    def collect(self, task_list, step_time):  # task是待传入数据的集合
        round_ = step_time
        termination = len(task_list)
        list = []
        arrive_time = 0
        for i in range(len(task_list)):
            if task_list[i].flag == 0:
                delay = round(self.formulas.transmission_sa_Delay(task_list[i]), 2)
                arrive_time += delay
                if arrive_time <= round_:
                    list.append(task_list[i])
                    task_list[i].flag = 2
                    task_list[i].arrive_time = arrive_time
                    task_list[i].delay['transmission'] += delay
                    round_ -= delay
                    termination -= 1
        return list









